module top #(
    parameter
        OV5640_ADDR             = 8'h3c                                 ,           
        SYS_FRQ                 = 26'd50_000_000                        ,           
        I2C_FREQ                = 18'd250_000                           ,           
        FRAME_TOTLE_H           = 16'd1856                              ,           
        FRAME_TOTLE_V           = 16'd984                               ,            
        FRAME_ROW               = 16'd480                               ,           // 一帧的行数
        FRAME_LINE              = 16'd640                               ,           // 一帧的列数，16bit为一个单位
        WR0_BURST_LEN           = FRAME_LINE >> 2                       ,           // wr0_fifo一次突发要突发的长度，一个突发地址对应8个ddr地址，8x16bit
        WR1_BURST_LEN           = FRAME_LINE >> 2                       ,           // wr1_fifo一次突发要突发的长度
        RD0_BURST_LEN           = FRAME_LINE >> 2                       ,           // rd0_fifo一次突发要突发的长度
        RD1_BURST_LEN           = FRAME_LINE >> 2                       ,           // rd1_fifo一次突发要突发的长度
        WR0_THRESHOLD           = FRAME_LINE >> 2                       ,           // wr0驱动ddr写的阈值——1行数据——单位 64bit
        WR0_THRESHOLD_BEGINE    = FRAME_LINE >> 2                       ,            
        WR1_THRESHOLD           = FRAME_LINE >> 2                       ,           // wr1驱动ddr写的阈值——1行数据——单位 64bit
        WR1_THRESHOLD_BEGINE    = FRAME_LINE >> 2                       ,            
        RD0_THRESHOLD           = FRAME_LINE                            ,           // rd0驱动ddr写的阈值——1行数据——单位 16bit
        RD1_THRESHOLD           = FRAME_LINE >> 2                       ,           // rd1驱动ddr写的阈值——1行数据——单位 128bit
        RD1_BEGIN_ADDR          = FRAME_ROW*FRAME_LINE*2                ,           // 614400~1228799
        WR1_BEGIN_ADDR          = FRAME_ROW*FRAME_LINE*2                ,           // 614400~1228799
        IMG_GET_FREAME_LIMITE   = 16'd2                                 ,                     
        GRAY_GET_FREAME_LIMITE  = 16'd3                                 ,                     
        DIFF_THRESHOLD          = 16'd3000                              ,           // 帧差二值化阈值
        BOX_COLOR               = 16'hffff                              ,           // 纯红
        SOBEL_THRESHOLD         = 128                                   ,            // sobel 阈值
        MIN_DIST                = 50                                    
)(
    input           sys_clk         ,  
    input           sys_rst_n       , // s0
    // eth
    input           eth_rxc         ,
    input           eth_rxctl       ,
    input  [3:0]    eth_rxd         ,
    input           key_eth_rst_n   , // s1
    input           key_arp_req     , // s2
    input           key_udp_tx      , // s4
    output          eth_txc         ,
    output          eth_txctl       ,
    output [3:0]    eth_txd         ,
    output          eth_rst_n       ,

    // ov5640
    input           cam_pclk        ,  
    input           img_vsync       ,
    input           img_href        , 
    input  [7:0]    img_data        ,  
    output          sccb_scl        ,  
    inout           sccb_sda        ,  
    output          cam_rst_n       , 
    output          cam_pwdn        ,  
    output          cam_xclk        ,
    output [7:0]    led             ,

    // ddr3
    inout  [15:0]   ddr3_dq         ,
    inout  [ 1:0]   ddr3_dqs_n      ,
    inout  [ 1:0]   ddr3_dqs_p      ,
    output [13:0]   ddr3_addr       ,
    output [ 2:0]   ddr3_ba         ,
    output          ddr3_ras_n      ,
    output          ddr3_cas_n      ,
    output          ddr3_we_n       ,
    output          ddr3_reset_n    ,
    output          ddr3_ck_p       ,
    output          ddr3_ck_n       ,
    output          ddr3_cke        ,
    output          ddr3_cs_n       ,
    output [ 1:0]   ddr3_dm         ,
    output          ddr3_odt        
);
// 系统
wire            clk_50m, clk_24m, clk_200m;
wire            locked, locked1;
wire            fifo_rst_n, ddr_rst_n;
wire            cam_pll_rst_n;
// ov5640
wire            ov5640_init_done;
wire            cam_clk;

// udp
wire            udp_tx_start;
wire [7:0]      udp_tx_data;
wire [15:0]     udp_tx_byte_num;
wire            fifo_rd_en;
wire            udp_tx_done;

// ddr
wire            ddr3_ui_clk;
wire            ddr3_init_done;

// rd0
wire            rd0_rd_en;
wire [15:0]     rd0_16bit_dout;

// rd1
wire            rd1_rd_en;
wire [127:0]    rd1_128bit_dout;

// wr0
wire [ 7:0]     wr0_8bit_din;
wire            wr0_wr_en;

// wr1
wire [ 15:0]    wr1_16bit_din;
wire            wr1_wr_en;

// 图像处理
wire [15:0]     img_data_o;     // rd0通道
wire            img_href_o;
wire            img_vsync_o;
wire            img_data_valid;
wire            gray_vsync;     // 灰度化
wire            gray_href;
wire [15:0]     gray_data;
wire            gray_data_valid; 
wire            gray_vsync_o;   // rd1通道
wire            gray_href_o;
wire [15:0]     pas_gray_data_o;
wire [15:0]     cur_gray_data_o;
wire            gray_data_valid_o;

// 帧差
wire            frame_data_vsync    ;
wire            frame_data_href     ;
wire [15:0]     frame1_gray_data    ;
wire [15:0]     frame2_gray_data    ;
wire            frame_data_valid    ;
wire            diff_data_vsync     ;
wire            diff_data_href      ;
wire [15:0]     diff_data           ;
wire            diff_data_valid     ;

// 腐蚀
wire        corr_img_vsync_o ;
wire        corr_img_href_o  ;
wire        corr_data_valid_o;
wire [15:0] corr_img_data_o  ;

// 膨胀
wire        expan_img_vsync_o ;
wire        expan_img_href_o  ;
wire        expan_data_valid_o;
wire [15:0] expan_img_data_o  ;

// sobel
wire        sobel_post_vsync;
wire        sobel_post_href ;
wire        sobel_post_de   ;
wire [15:0] sobel_post_rgb  ;

// coordinate
wire [15:0]     coord_x1   ;
wire [15:0]     coord_x2   ;
wire [15:0]     coord_y1   ;
wire [15:0]     coord_y2   ;

// 多目标
wire [655:0]    target_pos;
// output
wire            output_vsync;
wire            output_href ;
wire [15:0]     output_data ;

// 数据转换
wire            com_vsync_8b;
wire            com_hred_8b;
wire [7:0]      com_data_8b;

// main code-----------------------------------------
// 调试
 ila_0 u_ila (
 	.clk        (cam_clk),            // clk
 	.probe0     (corr_img_vsync_o  ), // 1bit
 	.probe1     (corr_img_href_o   ), // 1bit
 	.probe2     (corr_data_valid_o ), // 1bit
 	.probe3     (corr_img_data_o   ), // 16bit
    .probe4     (diff_data_vsync   ), // 1bit
    .probe5     (diff_data_href    ), // 1bit
    .probe6     (diff_data         ), // 16bit
    .probe7     (diff_data_valid_o)   // 1bit
 );

assign eth_rst_n = 1'd1;
assign cam_rst_n = 1'd1;
assign cam_pwdn  = 1'd0;
assign cam_xclk  = clk_24m; 
assign led[4]    = locked1;
assign led[5]    = locked;
assign led[6]    = ov5640_init_done;
assign led[7]    = ddr3_init_done;

// 系统时钟
clk_wiz_sys u_wiz(
    .clk_out1   (clk_50m    ),     
    .clk_out2   (clk_24m    ),     
    .clk_out3   (clk_200m   ),     
    .reset      (~sys_rst_n ), 
    .locked     (locked     ),
    .clk_in1    (sys_clk    )
);

// ov5640时钟
clk_wiz_cam u_wiz2(
    .clk_out1   (cam_clk        ),
    .reset      (~cam_pll_rst_n ),
    .locked     (locked1        ),
    .clk_in1    (cam_pclk       )
);

// 复位
rst_ctrl u_rst_ctrl(
    .clk        (clk_50m        ),
    .ddr_ui_clk (ddr3_ui_clk    ),
    .sys_rst_n  (sys_rst_n      ),
    .ddr_rst_n  (ddr_rst_n      ),
    .cam_rst_n  (cam_pll_rst_n  ),
    .fifo_rst_n (fifo_rst_n     ) // 给fifo
);

// ov5640驱动
ov5640 #(
    .OV5640_ADDR    (OV5640_ADDR  ),
    .SYS_FRQ        (SYS_FRQ      ),
    .I2C_FREQ       (I2C_FREQ     ),
    .FRAME_LINE     (FRAME_LINE   ),
    .FRAME_ROW      (FRAME_ROW    ),
    .FRAME_TOTLE_H  (FRAME_TOTLE_H),
    .FRAME_TOTLE_V  (FRAME_TOTLE_V)
) u_ov5640(
    .clk                (clk_50m         ),
    .rst_n              (sys_rst_n       ),
    .sccb_sda           (sccb_sda        ),
    .sccb_scl           (sccb_scl        ),
    .ov5640_init_done   (ov5640_init_done)
);

// 写给ddr3 wr0通道
img_data u_img_data(                    // img原始数据处理
    .clk            (cam_clk            ),
    .rst_n          (sys_rst_n          ),
    .img_vsync_i    (img_vsync          ),
    .img_href_i     (img_href           ),
    .img_data_i     (img_data           ),
    .init_done      (ov5640_init_done   ),
    .ddr_init_done  (ddr3_init_done     ),
    .fifo_wr_data   (wr0_8bit_din       ),
    .fifo_wr_en     (wr0_wr_en          ) 
);

// 读取ddr rd0通道数据
img_get_from_ddr #(
    .FRAME_ROW              (FRAME_ROW ),
    .FRAME_LINE             (FRAME_LINE),
    .IMG_GET_FREAME_LIMITE  (IMG_GET_FREAME_LIMITE)
) u_img_get_from_ddr(
    .clk                (cam_clk        ),
    .rst_n              (sys_rst_n      ),
    .img_href           (img_href       ),
    .img_vsync          (img_vsync      ),
    .input_fifo_rd_en   (rd0_rd_en      ),
    .fifo_rd_img_data   (rd0_16bit_dout ),
    .img_vsync_o        (img_vsync_o    ),
    .img_href_o         (img_href_o     ),
    .img_data_o         (img_data_o     ),
    .img_data_valid     (img_data_valid )
);

// 从ddr rd0通道获取的数据转灰度
rbg565_gray u_rbg565_gray(
    .cam_pclk           (cam_clk        ),
    .rst_n              (sys_rst_n      ),
    .cam_vsync          (img_vsync_o    ),
    .cam_href           (img_href_o     ),
    .cam_data           (img_data_o     ),
    .gray_vsync         (gray_vsync     ),
    .gray_href          (gray_href      ),
    .gray_data          (gray_data      ),
    .gray_data_valid    (gray_data_valid) 
);

// 灰度数据写入wr1
assign wr1_16bit_din = gray_data;
assign wr1_wr_en = gray_data_valid;

// 获取rd1的两帧灰度数据
gray_get_from_ddr #(
    .FRAME_ROW              (FRAME_ROW             ),
    .FRAME_LINE             (FRAME_LINE            ),
    .GRAY_GET_FREAME_LIMITE (GRAY_GET_FREAME_LIMITE)
) u_gray_get_from_ddr(
    .clk                (cam_clk            ),
    .rst_n              (sys_rst_n          ),
    .gray_href          (gray_href          ),
    .gray_vsync         (gray_vsync         ),
    .gray_data          (rd1_128bit_dout    ),
    .input_fifo_rd_en   (rd1_rd_en          ),
    .gray_vsync_o       (gray_vsync_o       ),
    .gray_href_o        (gray_href_o        ),
    .pas_gray_data_o    (pas_gray_data_o    ),
    .cur_gray_data_o    (cur_gray_data_o    ),
    .gray_data_valid_o  (gray_data_valid_o  )
);

// 帧差处理
assign frame1_gray_data = pas_gray_data_o;
assign frame2_gray_data = cur_gray_data_o;
assign frame_data_href  = gray_href_o;
assign frame_data_vsync = gray_vsync_o;
assign frame_data_valid = gray_data_valid_o;

frame_difference #(
    .DIFF_THRESHOLD(DIFF_THRESHOLD)    
) u_frame_difference(
    .frame_data_vsync   (frame_data_vsync   ),
    .frame_data_href    (frame_data_href    ),
    .frame1_gray_data   (frame1_gray_data   ),
    .frame2_gray_data   (frame2_gray_data   ),
    .frame_data_valid   (frame_data_valid   ),
    .diff_data_vsync    (diff_data_vsync    ),
    .diff_data_href     (diff_data_href     ),
    .diff_data_valid    (diff_data_valid    ),
    .diff_data          (diff_data          )
);

// 腐蚀
corrosion #(
    .FRAME_LINE(FRAME_LINE),
    .FRAME_ROW (FRAME_ROW )
) u_corrosion(
    .clk            (cam_clk           ),
    .rst_n          (sys_rst_n         ),
    .img_vsync      (diff_data_vsync   ),
    .img_href       (diff_data_href    ),
    .data_valid     (diff_data_valid   ),
    .img_data       (diff_data         ),
    .img_vsync_o    (corr_img_vsync_o  ),
    .img_href_o     (corr_img_href_o   ),
    .data_valid_o   (corr_data_valid_o ),
    .img_data_o     (corr_img_data_o   )
);

// 膨胀
expansion #(
    .FRAME_LINE(FRAME_LINE),
    .FRAME_ROW (FRAME_ROW )
) u_expansion(
    .clk                (cam_clk           ),
    .rst_n              (sys_rst_n         ),
    .img_vsync          (corr_img_vsync_o  ),
    .img_href           (corr_img_href_o   ),
    .data_valid         (corr_data_valid_o ),
    .img_data           (corr_img_data_o   ),
    .img_vsync_o        (expan_img_vsync_o ),
    .img_href_o         (expan_img_href_o  ),
    .data_valid_o       (expan_data_valid_o),
    .img_data_o         (expan_img_data_o  )
);

// 单组极值坐标获取
get_ex_coord #(
    .FRAME_LINE (FRAME_LINE),
    .FRAME_ROW  (FRAME_ROW )
) u_get_ex_coord(
    .clk                (cam_clk            ),
    .rst_n              (sys_rst_n          ),
    .diff_vsync         (expan_img_vsync_o  ),
    .diff_href          (expan_img_href_o   ),
    .diff_data_valid    (expan_data_valid_o ),
    .diff_data          (expan_img_data_o   ),
    .coord_x1           (coord_x1           ),
    .coord_x2           (coord_x2           ),
    .coord_y1           (coord_y1           ),
    .coord_y2           (coord_y2           )
);

// 多目标
// multi_obj_detect #(
//     .FRAME_LINE (FRAME_LINE),
//     .FRAME_ROW  (FRAME_ROW ),
//     .MIN_DIST   (MIN_DIST  )
// ) u_multi_obj_detect(
//     .clk                (cam_clk            ),
//     .rst_n              (sys_rst_n          ),
//     .pre_frame_vsync    (expan_img_vsync_o  ),
//     .pre_frame_href     (expan_img_href_o   ),
//     .pre_img_data_valid (expan_data_valid_o ),
//     .pre_img_data       (expan_img_data_o   ),
//     .pre_target_pos     (target_pos         )
// );

// 画目标框
input_box #(
    .FRAME_LINE (FRAME_LINE),
    .FRAME_ROW  (FRAME_ROW ),
    .BOX_COLOR  (BOX_COLOR)
) u_input_box(
    .clk            (cam_clk        ),
    .rst_n          (sys_rst_n      ),
    .pre_vsync      (img_vsync_o    ), // 待处理图像
    .pre_href       (img_href_o     ),
    .pre_data_valid (img_data_valid ),
    .pre_data       (img_data_o     ),
    // .pre_target_pos (target_pos     ),
    .coord_x1       (coord_x1       ),
    .coord_x2       (coord_x2       ),
    .coord_y1       (coord_y1       ),
    .coord_y2       (coord_y2       ),
    .post_vsync     (output_vsync   ), // 加框后的图像
    .post_href      (output_href    ),
    .post_data      (output_data    )
);

// sobel
// vip_sobel #(
//     .SOBEL_THRESHOLD    (SOBEL_THRESHOLD)
// ) u_vip_sobel(
//     .clk                (cam_clk            ),
//     .rst_n              (sys_rst_n          ),
//     .pre_frame_vsync    (gray_vsync         ),
//     .pre_frame_href     (gray_href          ),
//     .pre_frame_de       (gray_data_valid    ),
//     .pre_rgb            (gray_data          ),
//     .post_frame_vsync   (sobel_post_vsync   ),
//     .post_frame_href    (sobel_post_href    ),
//     .post_frame_de      (sobel_post_de      ),
//     .post_rgb           (sobel_post_rgb     )
// );

// 转换16bit为8bit数据丢给udp
bit16_bit8 u_bit16_bit8(
    .clk            (cam_clk        ),
    .rst_n          (sys_rst_n      ),
    .cam_vsync_16b  (diff_data_vsync), // 给udp的数据
    .cam_href_16b   (diff_data_href ),
    .cam_data_16b   (diff_data      ), // 16bit
    .cam_vsync_8b   (com_vsync_8b   ),
    .cam_hred_8b    (com_hred_8b    ),
    .cam_data_8b    (com_data_8b    )
);

// udp数据预处理
img_data_pkt u_pkt(
     .clk                (cam_clk          ),
     .rst_n              (sys_rst_n        ),
     .img_vsync_i        (com_vsync_8b     ),
     .img_href_i         (com_hred_8b      ),
     .img_data_i         (com_data_8b      ),      
     .init_done          (ov5640_init_done ),
     .udp_tx_clk         (eth_txc          ),
     .fifo_rd_en         (fifo_rd_en       ),
     .udp_tx_start       (udp_tx_start     ),
     .udp_tx_data        (udp_tx_data      ),
     .udp_tx_byte_num    (udp_tx_byte_num  )
);

// udp发送
eth_top u_eth(
    .eth_rxc            (eth_rxc        ),
    .eth_rxctl          (eth_rxctl      ),
    .eth_rxd            (eth_rxd        ),
    .sys_rst_n          (sys_rst_n      ),
    .key_eth_rst_n      (key_eth_rst_n  ),
    .key_arp_req        (key_arp_req    ),
    .key_udp_tx         (key_udp_tx     ),
    .tx_start           (udp_tx_start   ),
    .udp_fifo_rd_data   (udp_tx_data    ),
    .len_udp_data       (udp_tx_byte_num),
    .rd_data_count      (),
    .udp_fifo_rd_en     (fifo_rd_en     ),
    .udp_rx_data        (),
    .eth_txc            (eth_txc        ),
    .eth_txctl          (eth_txctl      ),
    .eth_txd            (eth_txd        ),
    .eth_rst_n          (eth_rst_n      ),
    .led                (led[3:0]       ),
    .udp_tx_done        (udp_tx_done    )
);

// ddr 实例化
ddr3_4port #(
    .FRAME_ROW              (FRAME_ROW              ),
    .FRAME_LINE             (FRAME_LINE             ),
    .WR0_BURST_LEN          (WR0_BURST_LEN          ),
    .WR1_BURST_LEN          (WR1_BURST_LEN          ),
    .RD0_BURST_LEN          (RD0_BURST_LEN          ),
    .RD1_BURST_LEN          (RD1_BURST_LEN          ),
    .WR0_THRESHOLD          (WR0_THRESHOLD          ),
    .WR0_THRESHOLD_BEGINE   (WR0_THRESHOLD_BEGINE   ),
    .WR1_THRESHOLD          (WR1_THRESHOLD          ),
    .WR1_THRESHOLD_BEGINE   (WR1_THRESHOLD_BEGINE   ),
    .RD0_THRESHOLD          (RD0_THRESHOLD          ),
    .RD1_THRESHOLD          (RD1_THRESHOLD          ),
    .RD1_BEGIN_ADDR         (RD1_BEGIN_ADDR         ),
    .WR1_BEGIN_ADDR         (WR1_BEGIN_ADDR         ),
    .GRAY_GET_FREAME_LIMITE (GRAY_GET_FREAME_LIMITE )
) u_ddr3_4port(
    .clk                (cam_clk        ),
    .sys_rst_n          (sys_rst_n      ),
    .rst_n              (fifo_rst_n     ),
    .clk_200m           (clk_200m       ),
    .ddr3_dq            (ddr3_dq        ),
    .ddr3_dqs_n         (ddr3_dqs_n     ),
    .ddr3_dqs_p         (ddr3_dqs_p     ),
    .ddr3_addr          (ddr3_addr      ),
    .ddr3_ba            (ddr3_ba        ),
    .ddr3_ras_n         (ddr3_ras_n     ),
    .ddr3_cas_n         (ddr3_cas_n     ),
    .ddr3_we_n          (ddr3_we_n      ),
    .ddr3_reset_n       (ddr3_reset_n   ),
    .ddr3_ck_p          (ddr3_ck_p      ),
    .ddr3_ck_n          (ddr3_ck_n      ),
    .ddr3_cke           (ddr3_cke       ),
    .ddr3_cs_n          (ddr3_cs_n      ),
    .ddr3_dm            (ddr3_dm        ),
    .ddr3_odt           (ddr3_odt       ),
    .ddr3_init_done     (ddr3_init_done ),
    .ddr3_ui_clk        (ddr3_ui_clk    ),
    .rd0_rd_clk         (cam_clk        ),
    .rd0_rd_en          (rd0_rd_en      ),
    .rd0_16bit_dout     (rd0_16bit_dout ),
    .wr0_wr_clk         (cam_clk        ),
    .wr0_8bit_din       (wr0_8bit_din   ),
    .wr0_wr_en          (wr0_wr_en      ),
    .rd1_rd_clk         (cam_clk        ),
    .rd1_rd_en          (rd1_rd_en      ),
    .rd1_128bit_dout    (rd1_128bit_dout),
    .wr1_wr_clk         (cam_clk        ),
    .wr1_16bit_din      (wr1_16bit_din  ),
    .wr1_wr_en          (wr1_wr_en      )
);
endmodule